package layouts;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashSet;
import java.util.Vector;

public class StuLayout implements LayoutManager, LayoutManager2 {

	private	HashSet<Component>			components;
	private Vector<Integer>				colPos;
	private Vector<Integer>				colSize;
	private Vector<Integer>				rowPos;
	private	Vector<Integer>				rowSize;
	private	int							sumColWidth;
	private int							sumRowHeight;
	private int							placeX, placeY;
	
	public StuLayout() {
		setSumColWidth(0);
		setSumRowHeight(0);
		colPos		= new Vector<Integer>();
		colSize		= new Vector<Integer>();
		rowPos		= new Vector<Integer>();
		rowSize		= new Vector<Integer>();
		components	= new HashSet<Component>();
		placeX = 0;
		placeY = 0;
		colPos.add(new Integer(0));
		rowPos.add(new Integer(0));
		colSize.add(new Integer(0));
		rowSize.add(new Integer(0));
	}
	
	public int	getNumCols() {
		return colSize.size();
	}
	public int	getNumRows() {
		return rowSize.size();
	}

	public int	getRegionWidth(int startCol, int numCols) {
		int	sum = 0;
		int	i;
		for(i=startCol; i<startCol+numCols; i++) {
			sum += colSize.get(i);
		}
		return sum;
	}
	
	public int	getRegionHeight(int startRow, int numRows) {
		int	sum = 0;
		int	i;
		for(i=startRow; i<=startRow+numRows; i++) {
			sum += rowSize.get(i);
		}
		return sum;
	}
	
	public Dimension getRegionSize(int startCol, int startRow, int numCols, int numRows) {
		return new Dimension(getRegionWidth(startCol, numCols), getRegionHeight(startRow, numRows));
	}

	public boolean putComponent(Component C, int col, int row, int colSpan, int rowSpan) {
		if (col<0)				return false;
		if (row<0)				return false;
		if (col>getNumCols()) 	return false;
		if (row>getNumRows())	return false;
		
		C.setLocation(colPos.get(col), rowPos.get(row));
		C.setSize(getRegionSize(col,row,colSpan,rowSpan));
		C.setVisible(true);
		return false;
	}
	
	public boolean addCol(int size) {
		int	idx = colSize.size();
		try {
			if (idx>0) {
				colSize.add(new Integer(size));
				colPos.add(new Integer( colPos.get(idx-1) + colSize.get(idx-1) ));
				setSumColWidth(getSumColWidth() + size);
			} else {
				colSize.add(new Integer(size));
				colPos.add(new Integer(0));
				setSumColWidth(getSumColWidth() + size);
			}
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	public boolean addRow(int size) {
		int	idx = colSize.size();
		try {
			if (idx>0) {
				rowSize.add(new Integer(size));
				rowPos.add(new Integer( rowPos.get(idx-1) + rowSize.get(idx-1) ));
				setSumRowHeight(getSumRowHeight() + size);
			} else {
				rowSize.add(new Integer(size));
				rowPos.add(new Integer(0));
				setSumRowHeight(getSumRowHeight() + size);
			}
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	public boolean removeCol(int col) {
		try {
			colSize.remove(col);
			colPos.remove(col);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	public boolean removeRow(int row) {
		try {
			rowSize.remove(row);
			rowPos.remove(row);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	
	public boolean setColWidth(int col, int size) {
		try {
			int	i;
			colSize.set(col,  new Integer(size));
			for(i=col+1; i < colPos.size(); i++) {
				colPos.set(i, new Integer( colPos.get(i-1) + colSize.get(i-1) ));
			}
			return true;
		} catch (ArrayIndexOutOfBoundsException e) {
			return false;
		}
	}
	
	public boolean setRowWidth(int row, int size) {
		try {
			int	i;
			rowSize.set(row,  new Integer(size));
			for(i=row+1; i < rowPos.size(); i++) {
				rowPos.set(i, new Integer( rowPos.get(i-1) + rowSize.get(i-1) ));
			}
			return true;
		} catch (ArrayIndexOutOfBoundsException e) {
			return false;
		}
	}
	
	private void nextPlacementPoint() {
		placeX = (placeX + 1) % (getNumCols());
		if (placeX==0) {
			placeY = (placeY + 1) % (getNumRows());
		}
	}

	@Override
	public void addLayoutComponent(String name, Component comp) {
		//
		// Adds components in a left to right manner. However This will
		// not take into account that a cell may already be covered by another
		// component
		//
		nextPlacementPoint();
		putComponent(comp, placeX, placeY, 1, 1);
	}

	@Override
	public void removeLayoutComponent(Component comp) {
		components.remove(comp);
	}

	@Override
	public Dimension preferredLayoutSize(Container parent) {
		return new Dimension(getSumColWidth(), getSumRowHeight());
	}

	@Override
	public Dimension minimumLayoutSize(Container parent) {
		return preferredLayoutSize(parent);
	}

	@Override
	public void layoutContainer(Container parent) {
		//
		// Do nothing. Everything is done apriori
		//
	}

	public int getSumColWidth() {
		return sumColWidth;
	}

	private void setSumColWidth(int sumColWidth) {
		this.sumColWidth = sumColWidth;
	}

	public int getSumRowHeight() {
		return sumRowHeight;
	}

	private void setSumRowHeight(int sumRowHeight) {
		this.sumRowHeight = sumRowHeight;
	}

	@Override
	public void addLayoutComponent(Component comp, Object constraints) {
		if (constraints.getClass().equals(Point.class)) {
			Point	P = (Point) constraints;
			this.putComponent(comp, P.x, P.y, 1, 1);
		} else if (constraints.getClass().equals(Rectangle.class)) {
			Rectangle	R = (Rectangle) constraints;
			this.putComponent(comp, R.x, R.y, R.width, R.height);
		} else if (constraints.getClass().equals(Dimension.class)) {
			Dimension D = (Dimension) constraints;
			nextPlacementPoint();
			this.putComponent(comp, placeX, placeY, D.width, D.height);
		}
	}

	@Override
	public Dimension maximumLayoutSize(Container target) {
		return target.getMaximumSize();
	}

	@Override
	public float getLayoutAlignmentX(Container target) {
		return 0;
	}

	@Override
	public float getLayoutAlignmentY(Container target) {
		return 0;
	}

	@Override
	public void invalidateLayout(Container target) {
		target.invalidate();
	}
}
